/**
 * 轮播图构造函数
 * @param obj.imgList       [必须]图片列表dom元素（ul）
 * @param obj.parentBox     [必须]父盒子框框dom元素
 * @param obj.currMarks     [可选]状态标记（ul,当前状态标记将动态添加名为active的类）
 * @param obj.arrows        [可选]箭头按钮（包含名为left和right属性的对象）
 * @param obj.count         [可选]每次显示的图片数量（默认为1）
 * @param obj.canDrag       [可选]设置是否可拖动，默认为false
 * @param obj.callback      [可选]状态变化后执行的回调函数，实参index
 * @constructor
 */
function Carousel(obj) {
    //定义属性初始值
    var defaultParam = {
        count: 1,
        canDrag: false,
        index: 0,
        isReady: true,
        isDragging: false
    };
    //实例属性混入继承自默认值对象与传入参数
    extend(this, defaultParam, obj);
    //初始化图片个数与父盒子宽度属性，如必须参数传入错误则打印异常，跳出函数
    try{
        this.imgLength = obj.imgList.children.length;
        this.boxWidth = obj.parentBox.offsetWidth / this.count;
    } catch(e) {
        console.error("请检查imgLength与parentBox是否正确传入！");
        return {};
    }
    //判断是否传入状态标记，有则获取标记dom子元素
    this.marks = obj.currMarks && obj.currMarks.nodeType ?
        obj.currMarks.children : null;
    //执行初始化方法
    this.init();
}
//替换轮播图构造函数原型
Carousel.prototype = {
    constructor: Carousel,
    init: function () {
        this.appendFirstImg();
        this.setIntv();
        this.bindEvent();
        this.canDrag ?
            this.bindDragEvent() : {};
    },
    /**
     * 将需要重复的图片克隆添加到列表最后
     */
    appendFirstImg: function () {
        for (var i = 0; i < this.count; i++) {
            this.imgList.appendChild(this.imgList.children[i].cloneNode(true));
        }
    },
    /**
     * 跳转到下一张
     */
    toNext: function () {
        if (!this.isReady) {
            return;
        }
        if (this.index >= this.imgLength) {
            this.imgList.style.left = 0;
            this.index = 0;
        }
        this.index++;
        this.changeMark(this.index);
        this.animate(this.imgList, {left: -this.index * this.boxWidth}, function () {
            if (this.index > this.imgLength) {
                this.imgList.style.left = 0;
            }
        });
    },
    /**
     * 跳转到上一张
     */
    toPrev: function () {
        if (!this.isReady) {
            return;
        }
        if (this.index <= 0) {
            this.imgList.style.left = -this.imgLength * this.boxWidth + "px";
            this.index = this.imgLength;
        }
        this.index--;
        this.changeMark(this.index);
        this.animate(this.imgList, {left: -this.index * this.boxWidth});
    },
    /**
     * 跳转到指定索引的图片
     * @param index
     */
    toJump: function (index) {
        this.index = index;
        this.animate(this.imgList, {left: -index * this.boxWidth});
        this.changeMark();
    },
    /**
     * 设置定时器
     */

    setIntv: function () {
        if (this.isDragging) {
            return;
        }
        var _this = this;
        _this.timerId = setInterval(function () {
            _this.toNext();
        }, 3000);
    },
    /**
     * 清除定时器
     */
    clearIntv: function () {
        clearInterval(this.timerId);
    },
    /**
     * 给DOM元素绑定事件
     */
    bindEvent: function () {
        var _this = this;
        //鼠标悬停时清除定时器，离开后重启
        _this.parentBox.addEventListener("mouseover", function () {
            _this.clearIntv();
        });
        _this.parentBox.addEventListener("mouseout", function () {
            _this.setIntv();
        });
        //绑定左右箭头按钮点击事件
        if (_this.arrows) {
            _this.arrows.left.addEventListener("click", function () {
                _this.toPrev();
            });
            _this.arrows.right.addEventListener("click", function () {
                _this.toNext();
            });
        }
        //绑定状态标识点击事件
        if (_this.marks) {
            for (var i = 0, len = _this.marks.length; i < len; i++) {
                _this.marks[i].index = i;
                _this.marks[i].addEventListener("click", function () {
                    _this.toJump(this.index);
                })
            }
        }
    },
    /**
     * 变更状态标记
     */
    changeMark: function () {
        var index = this.index === this.imgLength ? 0 : this.index
        if (this.marks) {
            for (var i = 0, len = this.marks.length; i < len; i++) {
                this.marks[i].classList.remove("active");
            }
            this.marks[index].classList.add("active");
        }
        if (this.callback) {
            this.callback(index);
        }
    },
    /**
     * 动画控制函数
     * @param element   需要添加动画的dom元素
     * @param data      动画变化数据
     * @param callback  动画结束时执行的回调函数
     */
    animate: function (element, data, callback) {
        var _this = this;
        _this.isReady = false;
        clearInterval(element.timerId);
        element.timerId = setInterval(function () {
            var flag = true;
            var leader, target, step;
            for (var Key in data) {
                if (Key === "opacity") {
                    leader = getStyle(element, Key) * 100 || 0;
                    target = data[Key] * 100;
                    step = (target - leader) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    leader = leader + step;
                    element.style[Key] = leader / 100;
                } else if (Key == "zIndex") {
                    leader = parseInt(getStyle(element, Key)) || 0;
                    target = data[Key];
                    step = (target - leader) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    leader = leader + step;
                    element.style[Key] = leader;
                } else {
                    leader = parseInt(getStyle(element, Key)) || 0;
                    target = data[Key];
                    step = (target - leader) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    leader = leader + step;
                    element.style[Key] = leader + "px";
                }
                if (target !== leader) {
                    flag = false;
                }
            }
            if (flag) {
                clearInterval(element.timerId);
                _this.isReady = true;
                if (callback) {
                    callback();
                }
            } else if (_this.isDragging) {
                clearInterval(element.timerId);
            }
        }, 20);
    },
    /**
     * 拖拽事件绑定
     */
    bindDragEvent: function () {
        var _this = this;
        //添加鼠标按下事件
        this.imgList.addEventListener("mousedown", function (e) {
            _this.isDragging = true;//改变拖拽状态标记
            e.preventDefault();//阻止默认事件
            _this.clearIntv();//清除轮播定时器
            //定义变量
            var startX = e.pageX;
            var moveMouse;
            var upMouse;
            var distance = 0;
            var leader = parseInt(getStyle(this, "left"));
            var result = leader;
            //绑定鼠标移动与松开事件（鼠标可能移出盒子外，为提高体验绑定了window）
            window.addEventListener("mousemove", moveMouse = function (e) {
                e.preventDefault();
                distance = e.pageX - startX;
                result = leader + distance;
                var maxLong = _this.imgLength * _this.boxWidth;
                if (result > 0) {
                    result -= maxLong;
                } else if (result < -maxLong) {
                    result += maxLong;
                }
                _this.imgList.style.left = result + "px";
            });
            window.addEventListener("mouseup", upMouse = function (e) {
                //清除拖拽状态
                _this.isDragging = false;
                var overflow = -result % _this.boxWidth;
                var index = parseInt(-result / _this.boxWidth);
                //判断滑动方向和滑动距离进行动画跳转
                _this.toJump(distance > 0 ?
                    (overflow > _this.boxWidth * 2 / 3 ? ++index : index) :
                    (overflow > _this.boxWidth / 3 ? ++index : index));
                //清除此次绑定的鼠标移动和移动松开事件
                this.removeEventListener("mousemove", moveMouse);
                this.removeEventListener("mouseup", upMouse);
            });
        });
    }
};
/**
 * 旋转木马构造函数
 * @param obj.parentBox     [必须]图片列表大盒子（div/ul）
 * @param obj.imagesList    [必须]图片列表dom元素（lis）
 * @param obj.styleData     [必须]样式数据（对象数组）
 * @param obj.currMarks     [可选]状态标记（ul,当前状态标记将动态添加名为active的类）
 * @param obj.arrows        [可选]箭头按钮（包含名为left和right属性的对象）
 * @param obj.callback      [可选]状态变化后执行的回调函数，实参index
 */
function MerryGoRound(obj) {
    var defaultParam = {
        isReady: true
    };
    extend(this,defaultParam,obj);
    this.init();
}
//旋转木马原型继承自轮播图原型
MerryGoRound.prototype = extCreate(Carousel.prototype);
//重写不同部分的属性
extend(MerryGoRound.prototype,{
    constructor: MerryGoRound,
    /**
     * 初始化函数
     */
    init: function() {
        this.assign();
        this.setIntv();
        this.bindEvent();
    },
    /**
     * 将样式数据应用到传入的dom元素中
     */
    assign: function() {
        for (var i = 0,len = this.imagesList.length; i < len; i++) {
            this.animate(this.imagesList[i],this.styleData[i]);
        }
    },
    /**
     * 跳转到下一张
     */
    toNext: function () {
        if (!this.isReady) {
            return;
        }
        this.styleData.unshift(this.styleData.pop());
        this.assign();
    },
    /**
     * 跳转到上一张
     */
    toPrev: function () {
        if (!this.isReady) {
            return;
        }
        this.styleData.push(this.styleData.shift());
        this.assign();
    },
});

/**
 * 混入继承
 * @returns {{}}
 */
function extend() {
    var arg0 = arguments[0];
    for (var i = 1, len = arguments.length; i < len; i++) {
        for (var key in arguments[i]) {
            arg0[key] = arguments[i][key];
        }
    }
}
/**
 * 经典继承
 * @param parent 父对象
 * @returns {F}
 */
function extCreate(parent) {
    function F() {
    }

    F.prototype = parent;
    return new F();
}
/**
 * 获取样式兼容
 * @param ele   dom元素
 * @param attr  属性名
 * @returns {*} 属性值
 */
function getStyle(ele, attr) {
    if (ele.currentStyle) {
        return ele.currentStyle[attr];
    } else {
        return getComputedStyle(ele, null)[attr];
    }
}

